﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Core.EntityClient;
using System.Linq;
using System.Text;
using WinnerCMS.Common;
using WinnerCMS.Model;
using WinnerCMS.Model.Enum;

namespace WinnerCMS.Data
{
    /// <summary>
    /// 栏目
    /// </summary>
    public class CategoryDal
    {
        private static readonly ConcurrentDictionary<int, IList<Category>> DicFatherAndMe;
        private static readonly ConcurrentDictionary<int, IEnumerable<Category>> DicChildren;
        private static readonly ConcurrentDictionary<int, IList<Category>> DicDescendants;
        public static readonly Dictionary<int, Category> Alllist;
        static CategoryDal()
        {
            Alllist = new CategoryDal().GetInfos();
            DicFatherAndMe = new ConcurrentDictionary<int, IList<Category>>();
            DicChildren = new ConcurrentDictionary<int, IEnumerable<Category>>();
            DicDescendants = new ConcurrentDictionary<int, IList<Category>>();
            DicDescendantIds = new ConcurrentDictionary<int, IEnumerable<int>>();
        }

        #region 添加栏目
        /// <summary>
        /// 添加栏目
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public int Add(Category model)
        {
            using (Entities db = new Entities())
            {
                model.Path = string.Empty;
                if (model.ParentId == 0)//如果是要添加顶级栏目
                {
                    bool exists = db.Categoryes.Any(x => x.ModelId == model.ModelId);
                    if (exists == false)
                    {
                        db.Categoryes.Add(model);
                        db.SaveChangesAsync().Wait();
                    }
                    else
                    {
                        model.OrderId = db.Categoryes.Where(x => x.ModelId == model.ModelId).Select(x => x.OrderId).DefaultIfEmpty(-1).Max() + 1;
                        db.Categoryes.Add(model);
                        db.SaveChangesAsync().Wait();
                    }
                    model.Path = "|" + model.Id + "|";
                    db.SaveChangesAsync().Wait();
                }
                else//如果不是要添加顶级栏目
                {
                    var pinfo = db.Categoryes.FirstOrDefault(x => x.Id == model.ParentId);

                    var orther = from x in db.Categoryes
                                 where x.OrderId > pinfo.OrderId
                                 && !x.Path.StartsWith(pinfo.Path)
                                 && x.ModelId == pinfo.ModelId
                                 select x;
                    foreach (var v in orther)
                    {
                        v.OrderId = v.OrderId + 1;
                    }
                    db.SaveChangesAsync().Wait();


                    model.OrderId = db.Categoryes.Where(x => x.Path.StartsWith(pinfo.Path)).Select(x => x.OrderId).DefaultIfEmpty(-1).Max() + 1;

                    db.Categoryes.Add(model);
                    db.SaveChangesAsync().Wait();

                    model.Path = pinfo.Path + model.Id + "|";
                    db.SaveChangesAsync().Wait();
                }

            }

            //给超管加上权限
            SaveCategoryRole(new[] { model.Id }, 1);
            return model.Id;
        }
        #endregion

        #region 保存栏目
        /// <summary>
        /// 保存栏目
        /// </summary>
        /// <param name="model"></param>
        public void Edit(Category model)
        {
            using (Entities db = new Entities())
            {
                db.Categoryes.Attach(model);
                db.Entry(model).State = EntityState.Modified;
                db.SaveChangesAsync().Wait();
            }
        }
        #endregion

        #region 取得所有栏目信息
        /// <summary>
        /// 取得所有栏目信息
        /// </summary>
        /// <returns></returns>
        public Category GetInfo(int id)
        {
            using (Entities db = new Entities())
            {
                db.Configuration.ProxyCreationEnabled = false;
                return db.Categoryes.AsNoTracking().FirstOrDefault(x => x.Id == id &&
                                                                             x.Model.Hide == false);
            }
        }
        #endregion

        #region 取得所有栏目信息
        /// <summary>
        /// 取得所有栏目信息
        /// </summary>
        /// <returns></returns>
        public Dictionary<int, Category> GetInfos()
        {
            using (Entities db = new Entities())
            {
                db.Configuration.ProxyCreationEnabled = false;
                db.ChangeTracker.DetectChanges();
                return db.Categoryes.Include(x => x.Model).AsNoTracking().Where(x => x.Model.Hide == false).ToDictionary(x => x.Id, x => x);
            }
        }
        /// <summary>
        /// 取得所有栏目信息
        /// </summary>
        /// <param name="modelId">模型id</param>
        /// <returns></returns>
        public IList<Category> GetInfos(byte modelId)
        {
            using (Entities db = new Entities())
            {
                db.Configuration.ProxyCreationEnabled = false;
                return db.Categoryes.AsNoTracking().Where(x => x.Model.Hide == false && x.ModelId == modelId).ToArray();
            }
        }
        #endregion

        #region 检查一下栏目下面是否还有数据
        /// <summary>
        /// 检查一下栏目下面是否还有数据
        /// </summary>
        /// <param name="categoryId"></param>
        /// <returns></returns>
        public int HaveData(int categoryId)
        {
            using (Entities db = new Entities())
            {
                var info = db.Categoryes.Include(x => x.Model).First(x => x.Id == categoryId);

                string sql = "SELECT TOP 1 Id FROM CMS_Cores WHERE CategoryId IN (select Id from CMS_Categories WHERE Path like '%|" + categoryId + "|%')";
                return db.Database.SqlQuery<int>(sql).FirstOrDefault();
            }
        }
        #endregion

        #region 获取全部子孙Id

        private static readonly ConcurrentDictionary<int, IEnumerable<int>> DicDescendantIds;

        /// <summary>
        /// 获取全部子孙Id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public IEnumerable<int> GetDescendantIds(int id)
        {
            IEnumerable<int> ids;

            return DicDescendantIds.GetOrAdd(id, item =>
            {
                string str = "|" + id + "|";
                ids = from x in Alllist.Values where x.Model.Hide == false && x.Path.Contains(str) select x.Id;

                return ids;
            });
        }

        public IEnumerable<Category> GetSonId(int pId)
        {
            using (Entities db = new Entities())
            {
                var query = from c in db.Categoryes
                            where c.ParentId == pId
                            orderby c.OrderId
                            select c;

                return query.ToArray().Concat(query.ToArray().SelectMany(t => GetSonId(t.Id)));
            }
        }
        #endregion

        #region 給栏目管理绑定数据
        /// <summary>
        /// 給栏目管理绑定数据
        /// </summary>
        /// <returns></returns>
        public IList<Category> BindList(byte? modelId)
        {
            return CategoryDataSouce(BindOption.All, modelId);
        }

        #region 绑定栏目的数据源
        /// <summary>
        /// 绑定栏目的数据源
        /// </summary>
        /// <param name="type"></param>
        /// <param name="modelId"></param>
        /// <returns></returns>
        private static IList<Category> CategoryDataSouce(BindOption type, byte? modelId)
        {
            if (type == BindOption.NoLink)//不显示外部链接的栏目
            {
                using (Entities db = new Entities())
                {
                    var q = from x in db.Categoryes
                            where x.LinkUrl == "" && (x.ModelId == modelId || modelId == null) && x.Model.Hide == false
                            select new { Id = x.Id, x.CategoryName, ParentId = x.ParentId, x.Path, OrderId = x.OrderId };
                    return q.ToArray().Select(x => new Category() { Id = x.Id, CategoryName = x.CategoryName, ParentId = x.ParentId, Path = x.Path, OrderId = x.OrderId }).ToArray();
                }
            }

            if (type == BindOption.All)
            {
                using (Entities db = new Entities())
                {
                    var q = from x in db.Categoryes
                            where (x.ModelId == modelId || modelId == null) && x.Model.Hide == false
                            select new { Id = x.Id, x.CategoryName, ParentId = x.ParentId, x.Path, x.LinkUrl, OrderId = x.OrderId, ModelId = x.ModelId, URLStyle = x.UrlStyle, CategoryURLStyle = x.CategoryUrlStyle };
                    return q.ToArray().Select(x => new Category() { Id = x.Id, CategoryName = x.CategoryName, ParentId = x.ParentId, Path = x.Path, LinkUrl = x.LinkUrl, OrderId = x.OrderId, ModelId = x.ModelId, UrlStyle = x.URLStyle, CategoryUrlStyle = x.CategoryURLStyle }).ToArray();
                }
            }
            return null;
        }

        #endregion

        #endregion

        #region 绑定Dll控件
        /// <summary>
        /// 绑定Dll控件
        /// </summary>
        /// <param name="Type"></param>
        /// <param name="modelId"></param>
        /// <returns></returns>
        public IList<Category> Bind_DDL(BindOption Type, byte? modelId)
        {
            return CategoryDataSouce(Type, modelId);
        }
        #endregion

        #region 栏目排序
        /// <summary>
        /// 栏目排序
        /// </summary>
        /// <param name="model"></param> 
        public void OrderByMove(Category model)
        {
            using (Entities db = new Entities())
            {
                var info = db.Categoryes.Find(model.Id);
                if (model.OrderType.ToUpper() == "UP")
                {
                    #region MyRegion
                    //上面的栏目
                    var Pre = db.Categoryes.Where(x => x.ParentId == info.ParentId && x.OrderId < info.OrderId).OrderByDescending(x => x.OrderId).FirstOrDefault();
                    if (Pre != null)
                    {
                        int MyOrderId = info.OrderId, PreOrderId = Pre.OrderId;

                        info.OrderId = PreOrderId;
                        Pre.OrderId = MyOrderId;

                        db.SaveChangesAsync().Wait();
                    }
                    #endregion
                }
                else
                {
                    #region MyRegion
                    //下面的栏目
                    var next = db.Categoryes.Where(x => x.ParentId == info.ParentId && x.OrderId > info.OrderId).OrderBy(x => x.OrderId).FirstOrDefault();
                    if (next != null)
                    {
                        int MyOrderId = info.OrderId, NextOrderId = next.OrderId;

                        info.OrderId = NextOrderId;
                        next.OrderId = MyOrderId;

                        db.SaveChangesAsync().Wait();
                    }

                    #endregion
                }
            }
        }
        #endregion

        #region 删除栏目
        /// <summary>
        /// 删除栏目
        /// </summary>
        /// <param name="id"></param>
        public void Delete(int id)
        {
            using (Entities db = new Entities())
            {
                var info = db.Categoryes.First(x => x.Id == id);
                info.Admins.Clear();
                info.Roles.Clear();
                db.Categoryes.Remove(info);
                db.SaveChangesAsync().Wait();
            }
        }
        /// <summary>
        /// 删除模型下所有栏目
        /// </summary>
        /// <param name="modelId"></param>
        public void Delete(byte modelId)
        {
            using (Entities db = new Entities())
            {
                var q = db.Categoryes.Where(x => x.ModelId == modelId);
                foreach (var v in q)
                {
                    db.Categoryes.Remove(v);
                }
                db.SaveChangesAsync().Wait();
            }
        }
        #endregion

        #region 清空栏目下的内容
        /// <summary>
        /// 清空栏目下的内容
        /// </summary>
        /// <param name="categoryId"></param>
        public void Clear(int categoryId)
        {
            using (Entities db = new Entities())
            {
                var info = db.Categoryes.Include(x => x.Model).First(x => x.Id == categoryId);
                db.Database.ExecuteSqlCommand("delete from CMS_Comments where ContentId in (select Id from " + info.Model.DataTable + " where CategoryId in (select Id from CMS_Categories where path like '%|" + categoryId + "|%')");

                //db.CMS_Comments.Where(x=>x.ContentCore.)

                db.Database.ExecuteSqlCommand("delete from " + info.Model.DataTable + " where CategoryId in (select Id from CMS_Categories where path like '%|" + categoryId + "|%')");
            }
        }
        #endregion

        #region 取得孩子栏目

        /// <summary>
        /// 取得孩子栏目
        /// </summary>
        /// <param name="parentId"></param>
        /// <returns></returns>
        public IEnumerable<Category> GetChildren(int parentId)
        {
            return DicChildren.GetOrAdd(parentId, item =>
             {
                 IEnumerable<Category> list = Alllist.Values;

                 IEnumerable<Category> infos = (from x in list
                                                where x.ParentId == parentId && x.Model.Hide == false
                                                orderby x.OrderId
                                                select x);

                 return infos;
             });
        }

        #endregion

        #region 获取全部子孙
        /// <summary>
        /// 获取全部子孙
        /// </summary>
        /// <param name="parentId"></param>
        /// <returns></returns>
        public IList<Category> GetDescendants(int parentId)
        {
            return DicDescendants.GetOrAdd(parentId, item =>
            {
                using (Entities db = new Entities())
                {
                    db.Configuration.ProxyCreationEnabled = false;
                    string str = "|" + parentId + "|";
                    var infos = (from x in db.Categoryes.AsNoTracking()
                                 where x.Model.Hide == false && x.Path.Contains(str) && x.Id != parentId
                                 orderby x.Path
                                 select x).ToArray();

                    return infos;
                }
            });
        }
        #endregion

        #region 查父栏目和本身
        /// <summary>
        /// 查父栏目和本身
        /// </summary>
        /// <param name="categoryId"></param>
        /// <returns></returns>
        public IList<Category> GetFatherAndMe(int categoryId)
        {
            return DicFatherAndMe.GetOrAdd(categoryId, item =>
            {
                Category me = GetInfo(categoryId);
                int[] ids = MyConvert.ConvertToArr(me.Path.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries));
                using (Entities db = new Entities())
                {
                    db.Configuration.ProxyCreationEnabled = false;
                    var list = db.Categoryes.Where(x => x.Model.Hide == false && ids.Contains(x.Id)).OrderBy(x => x.Path).ToArray();

                    return list;
                }
            });

        }

        #endregion



        #region 合并栏目

        /// <summary>
        /// 合并栏目
        /// </summary>
        /// <param name="oldCategoryId"></param>
        /// <param name="newCategoryId"></param>
        /// <param name="childCategory"></param>
        /// <param name="deleteCategory"></param>
        public Result MergeCategory(int oldCategoryId, int newCategoryId, bool childCategory, bool deleteCategory)
        {
            Result res = new Result();
            using (Entities db = new Entities())
            {
                if (db.Categoryes.Any(x => x.Path.Contains("|" + oldCategoryId + "|") && x.Id == newCategoryId))
                {
                    res.Errors = "不能合并到下级栏目";
                    return res;
                }

                if (childCategory)
                {
                    db.Database.ExecuteSqlCommand("UPDATE CMS_Cores SET CategoryId = {0} WHERE CategoryId ={1}", newCategoryId, oldCategoryId);
                }
                else
                {
                    db.Database.ExecuteSqlCommand("UPDATE CMS_Cores SET CategoryId = {0} WHERE CategoryId in (Select Id from CMS_Categories where Path like '%|" + oldCategoryId + "'|%' )", newCategoryId, oldCategoryId);
                }

                if (deleteCategory)
                {
                    Delete(oldCategoryId);
                }
            }
            return res;
        }
        #endregion

        #region 批量修改属性
        /// <summary>
        /// 批量修改属性
        /// </summary>
        /// <param name="selected"></param>
        /// <param name="values"></param>
        /// <param name="ids"></param>
        public void BatchUpData(IList<bool> selected, List<object> values, List<int> ids)
        {
            string[] ziDuan = {
"TemplateFileName",
"CategoryIntro",
"CategoryPic",
"CategoryDescription",
"CategoryKeyWord",
"ContentAdmin",
"CategoryAdmin",
"OpenGrade",
"EnableContribute",
"EnableComment",
"UrlRewrite",
"FilePostfix",
"FilePrefix",
"URLStyle",
"CategoryFilePostfix",
"CategoryFilePrefix",
"CategoryURLStyle" };

            MyStringBuilder strSql = new MyStringBuilder();
            strSql.Append("UPDATE CMS_Categories SET ");

            int index = 0;
            List<object> arr = new List<object>();
            for (int i = 0; i < selected.Count; i++)
            {
                if (selected[i])
                {
                    strSql.Append(string.Format("{0} = {{{1}}},", ziDuan[i], index));
                    arr.Add(values[i]);
                    index++;
                    //if (Values[i] is string)
                    //{
                    //    strSql.Append(string.Format("{0} = '{1}',", ZiDuan[i], Values[i]));
                    //}
                    //else
                    //{
                    //    strSql.Append(string.Format("{0} = {1},", ZiDuan[i], Values[i]));
                    //}
                }
            }

            strSql.TrimEnd();
            strSql.AppendFormat(" WHERE Id in ({0})", string.Join(",", ids));

            using (Entities db = new Entities())
            {
                db.Database.ExecuteSqlCommand(strSql.ToString(), arr.ToArray());
            }
        }
        #endregion

        #region 移动栏目
        /// <summary>
        /// 移动栏目
        /// </summary>
        /// <param name="id"></param>
        /// <param name="newPid"></param>
        public void Move(int id, int newPid)
        {
            using (Entities db = new Entities())
            {
                var info = db.Categoryes.Find(id);
                info.ParentId = newPid;
                info.OrderId = db.Categoryes.Where(x => x.ModelId == info.ModelId).Select(x => x.OrderId).DefaultIfEmpty(-1).Max() + 1;
                db.SaveChangesAsync().Wait();
            }
        }

        #endregion

        #region 获取管理员有权限的栏目
        /// <summary>
        /// 获取管理员有权限的栏目
        /// </summary>
        /// <param name="userid"></param>
        /// <returns></returns>
        public IList<Category> GetCategoryList(int userid)
        {
            using (Entities db = new Entities())
            {
                return db.Categoryes.Where(x => x.Admins.Any(y => y.Id == userid)).ToArray();
            }
        }
        #endregion

        #region 保存栏目权限(角色)
        /// <summary>
        /// 保存栏目权限(角色)
        /// </summary>
        /// <param name="categoryId"></param>
        /// <param name="roleid"></param>
        public void SaveCategoryRole(IEnumerable<int> categoryId, int roleid)
        {
            using (Entities db = new Entities())
            {
                var role = db.Roles.FirstOrDefault(x => x.Id == roleid);
                if (role == null)
                {
                    return;
                }
                db.Categoryes.Where(x => categoryId.Contains(x.Id)).ToArray().ForEach(x => role.Categoryes.Add(x));

                var users = db.Users.Where(x => x.Roles.Any(y => y.Id == roleid));

                db.Categoryes.Where(x => categoryId.Contains(x.Id)).ToArray()
                    .ForEach((x) =>
                        users.ForEach(u => u.CategoryForPermission.Add(x)));

                db.SaveChangesAsync().Wait();
            }
        }
        #endregion

    }
}